package tirateima.controlador;

import java.util.List;
import java.util.Stack;

import tirateima.gui.Principal;

/**
 * Modela um índice do Tira-Teima, que pode ser de matriz ou array de uma dimensão.
 * 
 * @author Luciano Santos
 */
public class Index {
	/** Valor do índice na primeira dimensão. */
	private Integer first = null;
	
	/** Nome da variável em que se encontra o valor do índice na primeira dimensão. */
	private Stack<Object> firstExpression;
	
	/** Valor do índice na segunda dimensão. */
	private Integer second = null;
	
	/** Nome da variável em que se encontra o valor do índice na segunda dimensão. */
	private Stack<Object> secondExpression;
	
	/** Define se o índice é de matriz. */
	public boolean isMatrix;
	
	/**
	 * construtor usado para criar um índice informando sua primeira e segunda dimensões, além de um valor informando se é matriz
	 * saber se é uma matriz.
	 * @param first
	 * @param second
	 * @param isMatrix
	 */
	public Index(Integer first, Integer second, boolean isMatrix) {
		this.first = first;
		this.second = second;
		this.isMatrix = isMatrix;
	}
	
	/**
	 * construtor usado quando se sabe que é uma matriz de duas dimensões
	 * @param first
	 * @param second
	 */
	public Index(Integer first, Integer second) {
		this(first, second, true);
	}
	
	/**
	 * construtor usado quando se sabe que o índice é um vetor
	 * @param first
	 */
	public Index(Integer first) {
		this(first, null, false);
	}
	
	/**
	 * construtor usado quando se sabe que o índice é um vetor sem dimensões
	 */
	public Index() {
		this(null, null, false);
	}
	
	
	
	public Integer getFirstIndexValue() {
		if (first != null) {
			return first;
		}
		else {
			Stack<Object> pilhaAuxiliar = new Stack<Object>();
			recuperaValoresVariaveis(firstExpression, pilhaAuxiliar, Principal.getInstance().control);
			Object value = AvaliadorDeExpressao.avaliar(pilhaAuxiliar);
			return Integer.valueOf(value.toString());
		}
	}
	
	public void setFirstIndexValue(Integer value) {
		first = value;
	}
	
	public void setFirstExpression(Stack<Object> expression) {
		firstExpression = expression;
	}
	
	
	public Integer getSecondIndexValue() {
		if (second != null) {
			return second;
		}
		else {
			Stack<Object> pilhaAuxiliar = new Stack<Object>();
			recuperaValoresVariaveis(secondExpression, pilhaAuxiliar, Principal.getInstance().control);
			Object value = AvaliadorDeExpressao.avaliar(pilhaAuxiliar);
			return Integer.valueOf(value.toString());
		}
	}
	
	public void setSecondIndexValue(Integer value) {
		second = value;
	}
	
	public void setSecondExpression(Stack<Object> expression) {
		secondExpression = expression;
	}
	
	
	
	/**
	 * Recupera os valores das variáveis colocando no lugar da pilha em que estava
	 * a variável o seu valor corrente para cálculo.
	 * 
	 * @param pilhaSimbolos
	 */
	@SuppressWarnings("unchecked")
	private void recuperaValoresVariaveis(Stack<Object> pilha, Stack<Object> pilhaAuxiliar,Controlador c) {
		Stack<Object> pilhaIntermediaria = new Stack<Object>();
		//passa os elementos para uma pilha intermediária
		while(!pilha.empty()){
			pilhaIntermediaria.push(pilha.pop());
		}
		/*pega cada elemento e coloca na pilha auxiliar, e devolve-o à pilha de 
		 * símbolos original.*/
		while(!pilhaIntermediaria.empty()){
			Object elemento = pilhaIntermediaria.pop();
			if(elemento instanceof List){
				pilhaAuxiliar.push(Command.getValue(c, (List<Object>)elemento));
			}
			else{
				pilhaAuxiliar.push(elemento);
			}
			pilha.push(elemento);
		}
	}
	
}
